﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using EasyStep.Business;
using EasyStep.Business.Interfaces;
using EasyStep.Attributes;
using EasyStep.Data.Entities;
using EasyStep.TestExecution.Data;
using EasyStep.TestEditor.Test;
using EasyStep.TestExecution;

namespace EasyStep.WinForms.Controls
{
    public partial class TestStepViewControl : UserControl
    {
        public ITestDataContext DataContext { get; set; }

        public List<TestStepResult> Data{ get; private set; }
        private TestStep stepinfo;
        private IEnumerable<TestAction> actions;
        Timer tmrDataRenderer = new Timer() { Interval = 100 };
        private ImageList ImagesList;
        public TestStepViewControl(TestStep data,IEnumerable<TestAction> allActions , ImageList resultImages)
        {
         
            ImagesList = resultImages;
            InitializeComponent();

            actions = allActions;
            stepinfo = data;
            CbAction.Enabled = false;
            CbSubAction.Enabled = false;
            ReInitResult();
            tmrDataRenderer.Tick += new EventHandler(tmrDataRenderer_Tick);
            tmrDataRenderer.Start();
        } 
       
        /// <summary>
        /// in that way rendering will be much more fast then synchronously 
        /// </summary>
        void tmrDataRenderer_Tick(object sender, EventArgs e)
        {
            var frm=ParentForm as ITestContextForm;
            if (frm==null)return;
            DataContext = frm.DataContext;
            tmrDataRenderer.Stop();
            if (stepinfo.ActionId != Guid.Empty)
            {
                stepinfo.Action = actions.Where(a => a.Id.Equals(stepinfo.ActionId)).FirstOrDefault();
                stepinfo.ActionId = stepinfo.Action == null ? Guid.Empty : stepinfo.Action.Id;
            }
            if (stepinfo.ActionId == Guid.Empty) stepinfo.Action = null;

            BindComboBox(CbAction, actions.Where(a => a.ParentId.Equals(Guid.Empty)), stepinfo.Action == null ? Guid.Empty : stepinfo.Action.ParentId);
            var cparent = CbAction.SelectedItem as TestAction;

            if (cparent != null)
                BindComboBox(CbSubAction, actions.Where(a => a.ParentId.Equals(cparent.Id)), stepinfo.ActionId);
            stepinfo.Action = CbSubAction.SelectedItem as TestAction;
            if (stepinfo!= null) BindTextBoxes(stepinfo);
            Refresh_Info(null, null);
            RefreshStatus();
        }


        private void Refresh_Info(object sender, EventArgs e)
        {
            if (this.Parent == null) return;
            var cnt=this.Parent.Controls.Count;
            lblInfo.Text = string.Format("{0}", cnt-this.Parent.Controls.GetChildIndex(this), this.Top);
        }
        private void BindComboBox(ComboBox cboxAction, IEnumerable<TestAction> steps, Guid selectedId,string displayMember="Name")
        {
            if (steps == null) return; 
            cboxAction.DisplayMember = displayMember;
            cboxAction.DataSource = steps.ToList();
            var selectedItem = steps.Where(i => i.Id.Equals(selectedId)).FirstOrDefault();
            if (selectedItem != null)
                cboxAction.SelectedItem = selectedItem;
        }

        protected void BindTextBoxes(TestStep withData)
        {
            if (withData.Locator != null && withData.Data != null)
                lblDetails.Text = String.Format("{0} / {1}", withData.Locator.Value, withData.Data.Value);
            else
            {
                var d = withData.Locator != null ? withData.Locator : withData.Data;
                lblDetails.Text = d==null?"-":d.Value;
            }
        }

        private void CbAction_SelectedIndexChanged(object sender, EventArgs e)
        {
            var parentId = ((TestAction)((ComboBox)sender).SelectedItem).Id;
            var subActions = DataContext.ActionManager.GetChildren(parentId).ToList();
            CbSubAction.Visible = subActions.Count() > 0;
            CbSubAction.DataSource = subActions;
            BindTextBoxes(stepinfo);
        }

        private void CbSubAction_SelectedIndexChanged(object sender, EventArgs e)
        {
            BindTextBoxes(stepinfo);
        }

        public void SetResult(TestStepResult updatedData)
        {
            lock(Data)
            {
                BindTextBoxes(updatedData.StepInfo);
                var existing=Data.Where(r=>r.Browser.Equals(updatedData.Browser,StringComparison.OrdinalIgnoreCase)).FirstOrDefault();
                if (existing != null) Data.Remove(existing);
                    Data.Add(updatedData);
            }
            RefreshStatus();
        }
        public void ReInitResult()
        {
            Data = new List<TestStepResult>();
            RefreshStatus();
            ShowHideCompleteInfo(true);
        }

        public IEnumerable<TestStepResult> GetResults()
        {
            return Data;
        }

        public void RefreshStatus()
        {
            ///todo: for each browsers have to be setup correct semaphore 
            pnlResult.Controls.Clear();
            var lbl = CreateStatusLabel(AnalizeTestBrowserResult(Data), pnlResult);
            lbl.LinkClicked += (s, le) =>
            {
                ShowHideCompleteInfo();
            };            
            lbl.Update();            
        }

        private LinkLabel CreateStatusLabel(ExecutionResult status, Control parent)
        {
            var lbl = new LinkLabel() { Text = status.ToString(), ImageIndex = GetImageIndex(status), ImageList = this.ImagesList, AutoSize = true, Dock = DockStyle.Left, Margin = new Padding(10, 10, 10, 10), Padding = new System.Windows.Forms.Padding(20, 0, 10, 0), ImageAlign = ContentAlignment.MiddleLeft, TextAlign = ContentAlignment.MiddleLeft, LinkBehavior = LinkBehavior.HoverUnderline };
            if (status == ExecutionResult.NoResult) lbl.Text = "";
            parent.Controls.Add(lbl);
            var width = lbl.Width;
            lbl.AutoSize = false;
            lbl.Width = width;
            return lbl;
        }

        private PictureBox CreateScreenshotPBox(string path, Control parent)
        {
            Image data = null;
            if (!string.IsNullOrEmpty(path) && System.IO.File.Exists(path))
                 try
                    {
                        var img= Image.FromFile(path);
                        data = new System.Drawing.Bitmap(img);                        
                        img.Dispose();
                        img=null;
                    }
                    catch (Exception ex)
                    {
                        DataContext.Log.Error("can't read screenshot file form:" + path, ex);
                    }
            if (data == null) return null;
            var pbox = new PictureBox() { Image = data, BorderStyle = System.Windows.Forms.BorderStyle.None, Dock = DockStyle.Left, SizeMode = PictureBoxSizeMode.Zoom };
            parent.Controls.Add(pbox);
            return pbox;
        }

        private void ShowHideCompleteInfo(bool hideOnly=false,Func<TestStep,IEnumerable<TestStepResult>> onMoreInfo=null)
        {
            pnlExInfo.SuspendLayout();
            var totalHeight = 0;
            pnlExInfo.Height = totalHeight;
            if (hideOnly || pnlExInfo.Controls.Count > 0) pnlExInfo.Controls.Clear();
            else
            {
                
                var dtoRender=onMoreInfo==null?Data:onMoreInfo(stepinfo);
                foreach (var item in Data)
                {
                    var bc = new GroupBox() { Name = "gbr_" + item.Browser, Dock = DockStyle.Top, Text = item.Browser };
                    pnlExInfo.Controls.Add(bc);
                    var txt = new TextBox() { Text = item.ExecutionLog.ToString(), Dock = DockStyle.Fill, Multiline = true, ScrollBars = ScrollBars.Vertical, WordWrap = true, ReadOnly = true };
                    bc.Controls.Add(txt);
                    var img = CreateScreenshotPBox(item.ScreenshotFile, bc);
                    if (img != null) img.Click += (s, e) =>
                    {
                        if (!string.IsNullOrEmpty(item.ScreenshotFile))
                            using(var p = System.Diagnostics.Process.Start(item.ScreenshotFile))
                            {
                                if (p!=null) p.Close();
                            }
                    };
                    var lbl = CreateStatusLabel(item.Result, bc);
                    lbl.Enabled = false;
                    if (img != null)
                        txt.Height = img.Height;
                    else
                        txt.Height = 50;
                    bc.Height = Math.Max(txt.Height,img==null?0: img.Height);
                    totalHeight += bc.Height;
                }
                pnlExInfo.Height =totalHeight;
            }
            pnlExInfo.PerformLayout();
            pnlExInfo.ResumeLayout();
            this.Height = pnlShortInfo.Height + totalHeight;
        }

        private ExecutionResult AnalizeTestBrowserResult(IEnumerable<TestStepResult> results)
        {
            if (!results.Any())
                return ExecutionResult.NoResult;
            if (results.Where(ri => ri.Result == ExecutionResult.Failed).Any())
                return ExecutionResult.Failed;
            if (results.Where(ri => ri.Result == ExecutionResult.InProgress).Any())
                return ExecutionResult.InProgress;
            return ExecutionResult.Success;
        }
        private int GetImageIndex(ExecutionResult result, bool forSelectedNode = false)
        {
            var index = ImagesList.Images.IndexOfKey(result.ToString());
            return index >= 0 ? index : 0;
        }

        private void this_MouseEnter(object sender, EventArgs e)
        {
            this.BackColor = System.Drawing.SystemColors.ControlLightLight;
        }

        private void this_MouseLeave(object sender, EventArgs e)
        {
            this.BackColor = System.Drawing.SystemColors.ControlLight;
        }
    }
}